﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Xml.Serialization;

namespace Robotics.Race
{
	public partial class frmDriverProfile : Form
	{
		private Controller profile = null;
		public Controller Profile { get { return profile; } set { profile = value; } }
		private List<Controller> profiles = new List<Controller>();
		private Type controllerType = null;
		private string controllerTypeName = null;

		public frmDriverProfile()
		{
			InitializeComponent();
			PopulateControllers();
			comboControllers.SelectedIndex = 0;
		}

		public void PopulateControllers()
		{
			TypeWrapper typeWrapper = new TypeWrapper();
			typeWrapper.TypeName = "None";
			typeWrapper.Type = null;
			comboControllers.Items.Add(typeWrapper);

			List<Type> types = ClassLoader.LoadTypesFromDLLs( typeof(Controller), ClassLoader.LoadDLLFileNames( ".", new string[]{"dll", "exe"} ) );
			foreach ( Type type in types )
			{
				string typeName = "";
				try
				{
					object[] result = type.GetCustomAttributes( typeof(ShortNameAttribute), false );
					if ( result != null && result.Length > 0 )
					{
						typeName = ( result[0] as ShortNameAttribute ).ShortName;
					}
					else
					{
						typeName = type.Name;
					}
				}
				catch (Exception)
				{
				}
				
				typeWrapper = new TypeWrapper();
				typeWrapper.TypeName = typeName;
				typeWrapper.Type = type;
				comboControllers.Items.Add( typeWrapper );
			}
		}

		private Controller loadedProfile;
		public void LoadProfile( Controller profile )
		{
			loadedProfile = profile;
			if ( profile == null )
				return;

			foreach ( object controller in comboControllers.Items )
			{
				if ((controller as TypeWrapper).Type == profile.GetType())
				{
					comboControllers.SelectedItem = controller;
					foreach ( object _profile in comboProfiles.Items )
					{
						if ( ( _profile as Controller ).Name == profile.Name )
						{
							this.Profile = _profile as Controller ;
							break;
						}
					}
					break;
				}
			}
		}

		public Controller SelectProfile()
		{
			ShowDialog();
			return Profile;
		}


		private void btSave_Click( object sender, EventArgs e )
		{
			try
			{
				if ( controllerType != null )
				{
					string profilePath = Path.Combine( Path.GetDirectoryName( Application.ExecutablePath ), "Profiles" );
					System.IO.Directory.CreateDirectory( profilePath );
					using ( System.IO.FileStream fs = new System.IO.FileStream( Path.Combine( profilePath, controllerTypeName + ".xml" ), FileMode.Create, FileAccess.Write ) )
					{
						Type controllerListType = typeof( List<> ).MakeGenericType( new Type[] { controllerType } );
						System.Reflection.MethodInfo method = typeof( ListConverter ).GetMethod( "ConvertList" ).MakeGenericMethod( new Type[] { controllerType, typeof( Controller ) } );
						object o = method.Invoke( null, new object[] { profiles } );

						XmlSerializer serializer = new XmlSerializer( controllerListType );
						serializer.Serialize( fs, o );
					}
				}
				Close();
			}
			catch ( Exception ex )
			{
				MessageBox.Show( "Save was unsuccessful. Reason: " + ex.ToString() );
			}
		}

		private void btCancel_Click( object sender, EventArgs e )
		{
			Profile = loadedProfile;
			Close();
		}

		private void comboControllers_SelectedIndexChanged( object sender, EventArgs e )
		{
			TypeWrapper wrappedControllerType = (TypeWrapper)comboControllers.SelectedItem;
			controllerType = wrappedControllerType.Type;
			controllerTypeName = wrappedControllerType.TypeName;
			if ( controllerType == null )
			{
				comboProfiles.SelectedItem = pgProperties.SelectedObject = Profile = null;
				btDelete.Enabled = btNew.Enabled = comboProfiles.Enabled = pgProperties.Enabled = false;
			}
			else
			{
				LoadProfiles();
				comboProfiles.SelectedItem = pgProperties.SelectedObject = Profile = profiles[0];
				btDelete.Enabled = btNew.Enabled = comboProfiles.Enabled = pgProperties.Enabled = true;
			}
		}

		private void LoadProfiles()
		{
			profiles.Clear();
			try
			{
				string profilePath = Path.Combine( Path.GetDirectoryName( Application.ExecutablePath ), "Profiles" );
				System.IO.Directory.CreateDirectory( profilePath );
				using ( System.IO.FileStream fs = new System.IO.FileStream( Path.Combine( profilePath, controllerTypeName + ".xml" ), FileMode.OpenOrCreate, FileAccess.Read ) )
				{
					Type controllerListType = typeof( List<> ).MakeGenericType( new Type[] { controllerType } );
					XmlSerializer serializer = new XmlSerializer( controllerListType );
					object o = serializer.Deserialize( fs );
					System.Reflection.MethodInfo method = typeof( ListConverter ).GetMethod( "ReversedConvertList" ).MakeGenericMethod( new Type[] { controllerType, typeof( Controller ) } );
					profiles = (List<Controller>)(method.Invoke( null, new object[] { o } ));
					comboProfiles.Items.Clear();
					profiles.ForEach( delegate (Controller c) { comboProfiles.Items.Add(c); } );
				}
			}
			catch ( Exception )
			{
			}
			if ( profiles.Count == 0 )
				CreateNewProfile();
		}

		private void comboProfileName_SelectedIndexChanged( object sender, EventArgs e )
		{
			pgProperties.SelectedObject = Profile = comboProfiles.SelectedItem as Controller;
		}

		private void btNew_Click( object sender, EventArgs e )
		{
			CreateNewProfile();
		}

		private void CreateNewProfile()
		{
			Profile = Activator.CreateInstance( controllerType ) as Controller;
			Profile.Name = CreateUniqueProfileName();
			profiles.Add( Profile );
			comboProfiles.Items.Add( Profile );
			comboProfiles.SelectedItem = Profile;
		}

		private string CreateUniqueProfileName()
		{
			string name = "";
			int i = 0;
			do
			{
				++i;
				name = "Profile" + i;
			} while ( profiles.Find(delegate (Controller c) { return c.Name == name; } ) != null );
			return name;
		}

		private void pgProperties_PropertyValueChanged( object s, PropertyValueChangedEventArgs e )
		{
			comboProfiles.Refresh();
		}

		private void btDelete_Click( object sender, EventArgs e )
		{
			profiles.Remove( Profile );
			comboProfiles.Items.Remove( Profile );
			if ( profiles.Count > 0 )
			{
				comboProfiles.SelectedItem = Profile = profiles[0];
			}
			else
			{
				CreateNewProfile();
			}
		}
	}
}
